﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SSharp.Core.DataTypes;

namespace SSharp.Core.Evaluator {
	public static partial class Eval {
		/// <summary>
		/// Note that this evaluator must come after all special forms and macros; it accepts any application, i.e. any parenthesised expression.
		/// </summary>
		private class ApplicationEvaluator : Evaluator {
			public bool CanEvaluate(object expression) {
				return expression is Cons;
			}

			public EvaluationResult Evaluate(object expression, IEnvironment env) {
				// evaluate an application: evaluate all the parameters, and then call Apply.

				Cons cons = (Cons)expression;
				object func = cons.car;
				IList<object> args = List.Unpack(cons.cdr);
				if (args == null) {
					throw new SyntaxError("Application cannot accept . parameters");
				}

				func = Eval.Evaluate(func, env);

				if (func is Macro) {
					// macros don't have their arguments evaluated before applying.
					return Apply.ApplyMacro((Macro)func, args, env);
				}

				// We use ToArray to force the evaluation to happen before application
				return Apply.ApplyFunction(func,
					args.Select(arg => Eval.Evaluate(arg, env)).ToArray());
			}
		}
	}
}
